import { alertBox, dangerIcon, dialogPanel, dialogStyle } from './dialog.css';
import '../../dict/dict';
import SVGWarning from '@mdi/svg/svg/alert-outline.svg';
import SVGSuccess from '@mdi/svg/svg/check-bold.svg';
import SVGError from '@mdi/svg/svg/close-thick.svg';
import SVGTips from '@mdi/svg/svg/lightbulb-on-outline.svg';
import SVGQuestion from '@mdi/svg/svg/message-question-outline.svg';
import { DICT } from '../../dict/dict';
import { knnoButton } from '../../theme/button.css';
import { knnoInput } from '../../theme/input.css';
import { vars } from '../../theme/vars.css';
import { DialogBase } from '../dialogBase';
import { Icon } from '../icon/icon';
import type { InputType } from '../inputType';

export class DialogBox extends DialogBase<DialogBox> {
	protected render() {
		return (
			<div class={[dialogStyle, 'dialog']}>
				<div class="container">
					<div class={dialogPanel} tabIndex={0}>
						<h2 aria-label="Dialog Header"></h2>
						<div class="content"></div>
						<div class="bar"></div>
					</div>
				</div>
			</div>
		);
	}
	protected get contentBox(): HTMLDivElement {
		return this.el.querySelector(`div.${dialogPanel}>div.content`)!;
	}
	get panel(): HTMLDivElement {
		return this.el.querySelector(`div.${dialogPanel}`)!;
	}

	setButtons(...buttons: Node[]): this {
		this.el.querySelector(`div.${dialogPanel}>div.bar`)?.replaceChildren(...buttons);
		return this;
	}

	setTitle(title: string): this {
		this.el.querySelector(`div.${dialogPanel}>h2`)!.textContent = title;
		return this;
	}

	setContent(content: (string | Node)[] | Node | string): this {
		if (Array.isArray(content)) {
			this.contentBox.replaceChildren(...content);
		} else {
			this.contentBox.replaceChildren(content);
		}
		return this;
	}

	setPadding(padding: string) {
		this.panel.style.padding = padding;
		return this;
	}
}

function iconAlert(
	icon: string | null,
	color: string,
	cancelButton = false,
): (msg: string, title?: string) => Promise<boolean> {
	return (msg: string, title?: string) => {
		return new Promise<boolean>((resolve) => {
			let result = false;
			const dlg = Dialog.create(
				<div class={alertBox}>
					{icon ? <Icon svg={icon} class={dangerIcon} style={{ fill: color }} /> : []}
					{msg}
				</div>,
			);
			dlg.el.addEventListener('close', () => {
				resolve(result);
			});
			const btns = [
				<button
					type="button"
					class={[knnoButton, 'primary']}
					onClick={() => {
						result = true;
						dlg.close({ result: 'ok' });
					}}
				>
					{DICT.ok}
				</button>,
			];
			if (cancelButton) {
				dlg.setEscClose(true);
				btns.unshift(
					<button
						type="button"
						class={knnoButton}
						onClick={() => {
							result = false;
							dlg.close();
						}}
					>
						{DICT.cancel}
					</button>,
				);
			}
			dlg.setButtons(...btns);
			if (title) {
				dlg.setTitle(title);
			}
			dlg.el.addEventListener('keypress', (evt) => {
				if (evt.key === 'Enter') {
					btns[cancelButton ? 1 : 0].dispatchEvent(new MouseEvent('click'));
				}
			});
			dlg.show();
		});
	};
}

type PromptOption = {
	message?: string;
	title?: string;
	placeholder?: string;
	type?: InputType;
	maxLength?: number;
	verify?: RegExp;
	verifyMessage?: string;
};

export const Dialog = {
	create(elem: (string | Node)[] | Node | string): DialogBox {
		const dlg = new DialogBox({});
		dlg.setContent(elem);
		return dlg;
	},

	alert(msg: string, title?: string): Promise<boolean> {
		return iconAlert(null, '')(msg, title);
	},

	error(msg: string, title?: string): Promise<boolean> {
		return iconAlert(SVGError, vars.color.danger)(msg, title);
	},

	success(msg: string, title?: string): Promise<boolean> {
		return iconAlert(SVGSuccess, vars.color.success)(msg, title);
	},

	warning(msg: string, title?: string): Promise<boolean> {
		return iconAlert(SVGWarning, vars.color.warning)(msg, title);
	},

	tips(msg: string, title?: string): Promise<boolean> {
		return iconAlert(SVGTips, vars.color.warning)(msg, title);
	},

	confirm(msg: string, title?: string): Promise<boolean> {
		return iconAlert(SVGQuestion, vars.color.accent, true)(msg, title);
	},

	prompt(options: PromptOption = {}): Promise<string | null> {
		return new Promise<string | null>((resolve) => {
			let result: string | null = null;
			const ipt = (<input class={knnoInput} required />) as HTMLInputElement;
			if (options.type) {
				ipt.type = options.type;
			}
			if (options.maxLength) {
				ipt.maxLength = options.maxLength;
			}
			if (options.placeholder !== undefined) {
				ipt.placeholder = options.placeholder;
			}
			ipt.addEventListener('input', () => {
				errDiv.textContent = '';
				ipt.classList.remove('verify');
			});
			ipt.pattern = `${options.verify ?? ''}`;
			ipt.addEventListener('keydown', (e) => {
				if (e.key === 'Enter') {
					onOK();
				}
			});
			const errDiv = (
				<div
					style={{
						color: vars.color.danger,
						textAlign: 'left',
						margin: '0.5em 0',
					}}
				/>
			);
			const dlg = Dialog.create([
				options.message ? <p style={{ textAlign: 'left' }}>{options.message}</p> : <></>,
				ipt,
				errDiv,
			])
				.setEscClose(true)
				.onClose(() => {
					resolve(result);
				})
				.setButtons(
					<button type="button" class={knnoButton} onClick={() => dlg.close()}>
						{DICT.cancel}
					</button>,
					<button type="button" class={[knnoButton, 'primary']} onClick={() => onOK()}>
						{DICT.ok}
					</button>,
				)
				.show({ focusElement: ipt });
			if (options.title) {
				dlg.setTitle(options.title);
			}
			function onOK() {
				result = ipt.value;
				if ((options.verify ?? /[^\s]+/).test(result)) {
					dlg.close({ result: 'ok' });
				} else {
					errDiv.textContent = options.verifyMessage ?? DICT.inputError;
					result = null;
					ipt.classList.add('verify');
					ipt.focus();
				}
			}
		});
	},
};
